Cortex-M33 on QEMUでアセンブリプログラミング
#RP2350
from Adafruit Metro RP2350
Cortex-M33 on QEMUでHelloWorld に続いて、Cortex-M33 on QEMUでアセンブリのコードを呼び出してみる。
Cortex-M33の命令セット
Thumb2 16ビット命令
https://www.aps-web.jp/wp-data/wp-content/uploads/2019/09/table01.pdf
Thumb2 32ビット命令
https://www.aps-web.jp/wp-data/wp-content/uploads/2019/09/table02.pdf
レジスタ
汎用レジスタ
R0 〜 R12
R0–R3:引数・戻り値(関数呼び出しで使用)
R4–R11:汎用(callee-saved)
push {r4, r5, r6, lr}
pop {r4, r5, r6, lr}
fp = r11
lr = r14
R12:一時用途(scratch register)
スタックポインタ
R13(SP)
リンクレジスタ
R14(LR)
関数戻りアドレスを保持
例外復帰情報も含む
プログラムカウンタ
R15(PC)
浮動小数点レジスタ
(本当?)
S0 〜 S31(単精度)
D0 〜 D15(倍精度として扱う)
FPSCR(ステータス)
参考
RP2350データシート
https://pip-assets.raspberrypi.com/categories/1214-rp2350/documents/RP-008373-DS-2-rp2350-datasheet.pdf?disposition=inline
アセンブリコードの呼び出し
code:diff
diff --git a/Makefile b/Makefile
index 497f2e0..6ae8481 100644
--- a/Makefile
+++ b/Makefile
@@ -15,13 +15,16 @@ LDFLAGS = \
-nostdlib \
-Wl,-Map=main.map
-OBJS = startup.o main.o
+OBJS = startup.o main.o fib.o
all: main.elf main.bin
main.elf: $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
+%.o: %.S
+ $(CC) $(CFLAGS) -c -o $@ $<
+
main.bin: main.elf
$(OBJCOPY) -O binary $< $@
diff --git a/fib.S b/fib.S
new file mode 100644
index 0000000..9957e00
--- /dev/null
+++ b/fib.S
@@ -0,0 +1,23 @@
+.syntax unified
+.thumb
+.global fib
+fib:
+ cmp r0, #1
+ bhi 1f
+ bx lr
+
+1:
+ movs r1, #0
+ movs r2, #1
+
+2:
+ adds r3, r1, r2
+ mov r1, r2
+ mov r2, r3
+ subs r0, r0, #1
+ cmp r0, #1
+ bhi 2b
+
+ mov r0, r2
+ bx lr
+
diff --git a/main.c b/main.c
index 0892a28..d63e77c 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,7 @@
#include <stdint.h>
+extern int fib(int n);
+
#define UART0_BASE 0x40200000u
typedef struct {
@@ -31,11 +33,34 @@ static void uart_puts(const char *s) {
}
}
+static void uart_print_int(int i) {
+ char buffer12; // Enough for -2147483648 and null terminator
+ int pos = 0;
+
+ if (i < 0) {
+ uart_putc('-');
+ i = -i;
+ }
+
+ do {
+ bufferpos++ = '0' + (i % 10);
+ i /= 10;
+ } while (i > 0);
+
+ // Reverse the buffer
+ for (int j = pos - 1; j >= 0; j--) {
+ uart_putc(bufferj);
+ }
+}
+
int main(void) {
uart_init();
uart_puts("Hello from QEMU mps2-an505 Cortex-M33!\n");
+ int result = fib(10);
+ uart_print_int(result);
+
while (1) {
}
}
浮動小数点命令の呼び出し
code:diff
diff --git a/Makefile b/Makefile
index 6ae8481..0264ddb 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,8 @@ OBJCOPY = arm-none-eabi-objcopy
CFLAGS = \
-mcpu=cortex-m33 \
-mthumb \
+ -mfpu=fpv5-sp-d16 \
+ -mfloat-abi=hard \
-ffreestanding \
-nostdlib \
-Wall \
@@ -15,7 +17,7 @@ LDFLAGS = \
-nostdlib \
-Wl,-Map=main.map
-OBJS = startup.o main.o fib.o
+OBJS = startup.o main.o fib.o fadd.o
all: main.elf main.bin
diff --git a/fadd.S b/fadd.S
new file mode 100644
index 0000000..1fabd57
--- /dev/null
+++ b/fadd.S
@@ -0,0 +1,12 @@
+.syntax unified
+.thumb
+.fpu fpv5-sp-d16
+
+.global fadd
+.type fadd, %function
+
+fadd:
+ vadd.f32 s0, s0, s1
+ bx lr
+
+.size fadd, . - fadd
diff --git a/main.c b/main.c
index d63e77c..557268b 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
#include <stdint.h>
extern int fib(int n);
+extern float fadd(float a, float b);
#define UART0_BASE 0x40200000u
@@ -58,8 +59,17 @@ int main(void) {
uart_puts("Hello from QEMU mps2-an505 Cortex-M33!\n");
+ // 整数演算を行うアセンブリ関数を呼び出す
int result = fib(10);
uart_print_int(result);
+ uart_putc('\n');
+
+ // 浮動小数点演算を行うアセンブリ関数を呼び出す
+ float a = 3.8f;
+ float b = 4.3f;
+ float c = fadd(a, b);
+ uart_print_int((int)c);
+ uart_putc('\n');
while (1) {
}
diff --git a/startup.c b/startup.c
index 1f94353..8a7b668 100644
--- a/startup.c
+++ b/startup.c
@@ -8,6 +8,8 @@ extern uint32_t _edata;
extern uint32_t _sbss;
extern uint32_t _ebss;
+#define SCB_CPACR (*(volatile uint32_t *)0xE000ED88u)
+
void Reset_Handler(void);
void Default_Handler(void) {
@@ -42,6 +44,10 @@ void (* const vector_table[])(void) = {
};
void Reset_Handler(void) {
+ SCB_CPACR |= (0xFu << 20);
+ __asm__ volatile ("dsb");
+ __asm__ volatile ("isb");
+
uint32_t *src = &_sidata;
uint32_t *dst = &_sdata;
実行結果。3.8 + 4.3 の結果8.1の整数部分8が出力されればOK
code:sh
$ make run
qemu-system-arm \
-machine mps2-an505 \
-cpu cortex-m33 \
-m 16M \
-nographic \
-monitor none \
-kernel main.elf
Hello from QEMU mps2-an505 Cortex-M33!
55
8
フィボナッチを手書きで
code:fib.S
.text
.syntax unified
.thumb
.global fib
fib:
push {r4, r5, r6, lr}
// n = 0 なら 0 を返す
cmp r0, #0
beq .Lreturn_zero
// n = 1 なら 1 を返す
cmp r0, #1
ble .Lreturn_one
// 元の n を保存
mov r6, r0
// r4 = fib(n - 1)
subs r0, r6, #1
bl fib
mov r4, r0
// r5 = fib(n - 2)
subs r0, r6, #2
bl fib
mov r5, r0
// r0 = fib(n - 1) + fib(n - 2)
adds r0, r4, r5
pop {r4, r5, r6, lr}
bx lr
.Lreturn_zero:
movs r0, #0
pop {r4, r5, r6, lr}
bx lr
.Lreturn_one:
movs r0, #1
pop {r4, r5, r6, lr}
bx lr